<template>
  <div class="qr-scanner">
    <el-card class="scanner-card" shadow="never">
      <template #header>
        <div class="card-header">
          <h2>二维码核验</h2>
          <p>请使用PDA或闸机摄像头扫描访客二维码进行核验</p>
        </div>
      </template>
      
      <!-- 扫描提示区 -->
      <div v-if="!visitorInfo" class="scan-area">
        <!-- 摄像头扫描界面 -->
        <div v-if="isScanning" class="camera-container">
          <video ref="videoRef" class="camera-video" autoplay playsinline></video>
          <canvas ref="canvasRef" class="camera-canvas" style="display: none;"></canvas>
          <div class="scan-overlay">
            <div class="scan-line"></div>
          </div>
        </div>
        
        <el-result v-else icon="info" title="准备扫描二维码">
          <template #sub-title>
            点击下方按钮开始扫描访客二维码
          </template>
          <template #extra>
            <el-button
              type="primary"
              size="large"
              :loading="isScanning"
              @click="startScan"
            >
              <el-icon><Camera /></el-icon>
              {{ isScanning ? '扫描中...' : '开始扫描' }}
            </el-button>
          </template>
        </el-result>
      </div>
      
      <!-- 访客信息展示 -->
      <div v-else class="visitor-section">
        <!-- 特殊访客提醒 -->
        <el-alert
          v-if="visitorInfo.is_special"
          type="warning"
          :title="`特殊访客 - ${visitorInfo.special_type}`"
          :closable="false"
          show-icon
          class="special-alert"
        />
        
        <!-- 访客信息 -->
        <el-descriptions
          title="访客信息"
          :column="2"
          border
          class="visitor-info"
        >
          <el-descriptions-item label="访客姓名">
            {{ visitorInfo.name }}
          </el-descriptions-item>
          <el-descriptions-item label="手机号码">
            {{ visitorInfo.phone }}
          </el-descriptions-item>
          <el-descriptions-item label="被访人">
            {{ visitorInfo.host_name }}
          </el-descriptions-item>
          <el-descriptions-item label="被访人电话">
            {{ visitorInfo.host_phone }}
          </el-descriptions-item>
          <el-descriptions-item label="预约时间">
            {{ formatDateTime(visitorInfo.visit_time) }}
          </el-descriptions-item>
          <el-descriptions-item label="访问事由">
            {{ visitorInfo.purpose }}
          </el-descriptions-item>
          <el-descriptions-item v-if="visitorInfo.company" label="公司">
            {{ visitorInfo.company }}
          </el-descriptions-item>
          <el-descriptions-item label="二维码有效期">
            {{ formatDateTime(visitorInfo.expires_at) }}
          </el-descriptions-item>
        </el-descriptions>
        
        <!-- 操作按钮 -->
        <div class="action-buttons">
          <el-button
            type="success"
            size="large"
            :loading="isSubmitting"
            @click="handleApprove"
          >
            <el-icon><SuccessFilled /></el-icon>
            允许通行
          </el-button>
          <el-button
            type="danger"
            size="large"
            :loading="isSubmitting"
            @click="showRejectDialog"
          >
            <el-icon><CircleCloseFilled /></el-icon>
            拒绝通行
          </el-button>
        </div>
        
        <!-- 重新扫描 -->
        <div class="rescan-section">
          <el-button text @click="resetScanner">
            扫描下一个二维码
          </el-button>
        </div>
      </div>
    </el-card>
    
    <!-- 拒绝原因对话框 -->
    <el-dialog
      v-model="rejectDialogVisible"
      title="拒绝原因"
      width="400px"
      :before-close="handleRejectDialogClose"
    >
      <el-input
        v-model="rejectReason"
        type="textarea"
        :rows="4"
        placeholder="请输入拒绝通行的具体原因..."
        maxlength="200"
        show-word-limit
      />
      <template #footer>
        <el-button @click="rejectDialogVisible = false">取消</el-button>
        <el-button
          type="danger"
          :loading="isSubmitting"
          @click="handleReject"
        >
          确认拒绝
        </el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, onUnmounted } from 'vue'
import { showError, showWarning, showSuccess } from '@/utils/message'
import {
  Camera,
  SuccessFilled,
  CircleCloseFilled
} from '@element-plus/icons-vue'
import { verificationApi } from '@/api/verification'
import { useAuthStore } from '@/stores/auth'
import type { VisitorInfo, VerificationSubmitRequest } from '@/types/verification'
import { formatDateTime } from '@/utils/date'
import jsQR from 'jsqr'

// 状态管理
const authStore = useAuthStore()

// 响应式状态
const isScanning = ref(false)
const isSubmitting = ref(false)
const visitorInfo = ref<VisitorInfo | null>(null)
const rejectDialogVisible = ref(false)
const rejectReason = ref('')

// 摄像头相关引用
const videoRef = ref<HTMLVideoElement | null>(null)
const canvasRef = ref<HTMLCanvasElement | null>(null)
const streamRef = ref<MediaStream | null>(null)
let scanInterval: number | null = null

/**
 * 开始扫描二维码
 */
const startScan = async (): Promise<void> => {
  try {
    isScanning.value = true
    
    // 检查是否在安全上下文（HTTPS）中运行
    if (!window.isSecureContext) {
      throw new Error('摄像头访问需要在安全上下文（HTTPS）中进行，请使用HTTPS协议访问应用')
    }
    
    // 检查浏览器是否支持媒体设备API
    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
      throw new Error('当前浏览器不支持摄像头访问，请使用最新版本的Chrome、Firefox或Safari浏览器')
    }
    
    // 获取摄像头权限
    const constraints: MediaStreamConstraints = {
      video: {
        facingMode: 'environment', // 优先使用后置摄像头
        width: { ideal: 1280 },
        height: { ideal: 720 }
      },
      audio: false
    }
    
    streamRef.value = await navigator.mediaDevices.getUserMedia(constraints)
    
    if (videoRef.value) {
      videoRef.value.srcObject = streamRef.value
    }
    
    // 开始扫描循环
    startScanningLoop()
    
  } catch (error) {
    console.error('获取摄像头权限失败:', error)
    // 提供更详细的错误信息
    let errorMessage = '无法访问摄像头，请检查权限设置'
    if (error instanceof Error) {
      if (error.name === 'NotAllowedError' || error.name === 'PermissionDeniedError') {
        errorMessage = '摄像头访问被拒绝，请在浏览器设置中允许摄像头权限'
      } else if (error.name === 'NotFoundError' || error.name === 'OverconstrainedError') {
        errorMessage = '未找到可用的摄像头设备'
      } else if (error.name === 'NotReadableError') {
        errorMessage = '摄像头设备不可用，请检查是否被其他应用占用'
      } else if (error.name === 'AbortError') {
        errorMessage = '摄像头访问被中断'
      } else if (error.message.includes('secure context')) {
        errorMessage = '摄像头访问需要HTTPS安全连接，请使用HTTPS协议访问应用'
      } else {
        errorMessage = error.message || '无法访问摄像头，请检查权限设置'
      }
    }
    showError(errorMessage)
    isScanning.value = false
  }
}

/**
 * 开始扫描循环
 */
const startScanningLoop = (): void => {
  if (scanInterval) {
    clearInterval(scanInterval)
  }
  
  scanInterval = window.setInterval(() => {
    scanQRCode()
  }, 500) // 每500ms扫描一次
}

/**
 * 扫描二维码
 */
const scanQRCode = (): void => {
  if (!videoRef.value || !canvasRef.value || !videoRef.value.videoWidth || !videoRef.value.videoHeight) {
    return
  }
  
  const canvas = canvasRef.value
  const context = canvas.getContext('2d')
  if (!context) return
  
  // 设置canvas尺寸与视频一致
  canvas.width = videoRef.value.videoWidth
  canvas.height = videoRef.value.videoHeight
  
  // 将视频帧绘制到canvas上
  context.drawImage(videoRef.value, 0, 0, canvas.width, canvas.height)
  
  // 获取图像数据
  const imageData = context.getImageData(0, 0, canvas.width, canvas.height)
  
  // 使用jsQR解码二维码
  const code = jsQR(imageData.data, imageData.width, imageData.height)
  
  if (code) {
    // 成功识别二维码
    handleQRCodeResult(code.data)
  }
}

/**
 * 处理二维码扫描结果
 * :param qrData: 二维码数据
 */
const handleQRCodeResult = async (qrData: string): Promise<void> => {
  try {
    // 停止扫描
    stopScan()
    
    // 调用核验API
    const response = await verificationApi.verifyQrCode({
      qr_data: qrData,
      guard_id: authStore.user?.id || 0
    })
    
    if (response.result === 'valid') {
      visitorInfo.value = response.visitor_info
    } else {
      handleVerificationError(response.result)
    }
    
  } catch (error) {
    console.error('二维码核验失败:', error)
    showError('二维码核验失败，请重试')
    // 重新开始扫描
    startScan()
  }
}

/**
 * 处理核验错误
 * :param result: 核验结果
 */
const handleVerificationError = (result: 'valid' | 'invalid' | 'expired' | 'blacklist'): void => {
  switch (result) {
    case 'invalid':
      showError('二维码无效')
      break
    case 'expired':
      showError('二维码已过期')
      break
    case 'blacklist':
      showError('访客在黑名单中，禁止通行')
      break
    default:
      showError('核验失败')
  }
  
  // 重新开始扫描
  setTimeout(() => {
    startScan()
  }, 2000)
}

/**
 * 停止扫描
 */
const stopScan = (): void => {
  if (scanInterval) {
    clearInterval(scanInterval)
    scanInterval = null
  }
  
  if (streamRef.value) {
    streamRef.value.getTracks().forEach(track => track.stop())
    streamRef.value = null
  }
  
  isScanning.value = false
}

/**
 * 处理允许通行
 */
const handleApprove = async (): Promise<void> => {
  if (!visitorInfo.value) return
  
  await submitVerification('pass')
}

/**
 * 显示拒绝对话框
 */
const showRejectDialog = (): void => {
  rejectDialogVisible.value = true
  rejectReason.value = ''
}

/**
 * 处理拒绝通行
 */
const handleReject = async (): Promise<void> => {
  if (!rejectReason.value.trim()) {
    showWarning('请填写拒绝原因')
    return
  }
  
  await submitVerification('reject', rejectReason.value)
  rejectDialogVisible.value = false
}

/**
 * 提交核验结果
 * :param result: 核验结果
 * :param rejectionReason: 拒绝原因（可选）
 */
const submitVerification = async (
  result: 'pass' | 'reject',
  rejectionReason?: string
): Promise<void> => {
  if (!visitorInfo.value || !authStore.user) return
  
  try {
    isSubmitting.value = true
    
    // 获取原始二维码数据（从视频流中获取的）
    // 注意：在实际实现中，您可能需要保存原始二维码数据
    const qrData = 'mock_qr_data' // 这里需要替换为实际的二维码数据
    
    const submitData: VerificationSubmitRequest = {
      qr_data: qrData,
      guard_id: authStore.user.id,
      result,
      ...(rejectionReason && { notes: rejectionReason })
    }
    
    await verificationApi.submitVerification(submitData)
    
    const message = result === 'pass' ? '已允许通行' : '已拒绝通行'
    showSuccess(message)
    
    // 重置扫描器
    resetScanner()
    
  } catch (error) {
    console.error('提交核验结果失败:', error)
    showError('提交失败，请重试')
  } finally {
    isSubmitting.value = false
  }
}

/**
 * 重置扫描器
 */
const resetScanner = (): void => {
  stopScan()
  visitorInfo.value = null
  rejectReason.value = ''
  rejectDialogVisible.value = false
}

/**
 * 处理拒绝对话框关闭
 */
const handleRejectDialogClose = (): void => {
  rejectReason.value = ''
}

/**
 * 组件卸载时清理资源
 */
onUnmounted(() => {
  resetScanner()
})
</script>

<style scoped>
.qr-scanner {
  max-width: 1000px;
  margin: 0 auto;
}

.scanner-card {
  border: none;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

.card-header h2 {
  margin: 0 0 8px 0;
  font-size: 18px;
  font-weight: 600;
  color: var(--el-text-color-primary);
}

.card-header p {
  margin: 0;
  color: var(--el-text-color-regular);
  font-size: 14px;
}

.scan-area {
  padding: 20px 0;
}

.camera-container {
  position: relative;
  width: 100%;
  max-width: 500px;
  margin: 0 auto;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.camera-video {
  width: 100%;
  height: auto;
  display: block;
  background: #000;
}

.camera-canvas {
  display: none;
}

.scan-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.scan-line {
  position: absolute;
  top: 20%;
  left: 10%;
  width: 80%;
  height: 2px;
  background: linear-gradient(90deg, transparent, #00ff00, transparent);
  animation: scan 2s linear infinite;
  box-shadow: 0 0 10px rgba(0, 255, 0, 0.5);
}

@keyframes scan {
  0% {
    top: 20%;
  }
  50% {
    top: 80%;
  }
  100% {
    top: 20%;
  }
}

.visitor-section {
  padding: 20px 0;
}

.special-alert {
  margin-bottom: 20px;
}

.visitor-info {
  margin-bottom: 24px;
}

.action-buttons {
  display: flex;
  gap: 16px;
  justify-content: center;
  margin-bottom: 24px;
}

.action-buttons .el-button {
  min-width: 140px;
}

.rescan-section {
  text-align: center;
  padding-top: 16px;
  border-top: 1px solid var(--el-border-color-lighter);
}

/* 响应式设计 */
@media (max-width: 768px) {
  .action-buttons {
    flex-direction: column;
  }
  
  .action-buttons .el-button {
    width: 100%;
  }
  
  .camera-container {
    max-width: 100%;
  }
}
</style>